package com.dsbj.mp.icardservice.config.intercept;

import com.alibaba.fastjson.JSON;
import com.dsbj.common.msg.ResponseMessage;
import com.dsbj.mp.icardservice.utils.Constants;
import com.dsbj.mp.icardservice.utils.StringHelper;
import com.dsbj.mp.icardservice.utils.encrypt.md5.MD5_fromWxpay;
import com.dsbj.mp.icardservice.utils.strprocess.StrUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Enumeration;
import java.util.LinkedHashMap;

/**
 * 签名验证拦截器，对请求的签名进行验证。
 * @author cjw 2019-11-26
 */
@Component
public class SignInterceptor extends HandlerInterceptorAdapter {
	
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	/**
	 * 验证请求的签名。暂时只支持GET请求的签名验证, 未验证POST请求签名。
	 * @param
	 * @return 
	 * @author cjw 2019-11-27
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		logger.info("执行了SignInterceptor.preHandle()方法..");
		
		//获取客户端提供的签名
		String sign=request.getHeader("sign");
		if(StrUtil.isEmpty(sign)){
			logger.error("[ip="+request.getRemoteAddr()+"] 未找到请求签名sign!");
			StringHelper.renderResponse(response, ResponseMessage.error("未找到请求签名sign!"));
			return false;
		}
		
		/**
		 * 根据请求方法类型，分别验证客户端提供的签名。
		 */
		// 获取请求类型
		String method = request.getMethod();
		boolean result = false;
		
		if (method.equals("GET")) {
			logger.info("本次请求为GET请求..");
			result = preHandle_get(request,response);
		} else {
			logger.info("本次请求为POST请求，暂时未验证该请求的签名，直接返回true..");
			//result = preHandle_post(request,response);
			result=true;
		}
		return result;
	}
	
	/**
	 * 验证get请求的签名。
	 * @param
	 * @return
	 * @author cjw 2019-11-27
	 */
	public boolean preHandle_get(HttpServletRequest request,HttpServletResponse response) throws Exception {
		
		/**
		 * 1、获取客户端提供的签名
		 */
		String sign=request.getHeader("sign");
		
		/**
		 * 2、获取传来的参数,并将以ISO-8859-1解码的字符串重新以UTF-8解码
		 */
		//获取token并存入params中
		LinkedHashMap<String, String> params = new LinkedHashMap<String, String>();
		String token=request.getHeader(Constants.USER_TOKEN);
		params.put(Constants.USER_TOKEN, token);
		
		//获取其他请求参数
		Enumeration<String> pNames = request.getParameterNames();
		String pName = null;
		String pValue = null;
		while (pNames.hasMoreElements()) {
			pName = pNames.nextElement();
			pValue = request.getParameter(pName);
			
			// 将以ISO-8859-1解码的字符串重新以UTF-8解码
			pName = new String(pName.getBytes("ISO-8859-1"), "UTF-8");
			
			/*
			 * 已在过滤器中对pvalue转码。 if(pValue!=null) { pValue=new
			 * String(pValue.getBytes("ISO-8859-1"),"UTF-8"); }
			 */
			params.put(pName, pValue);
		}
		StrUtil.prettyPrintWithTime("params",params);
		
		/**
		 * 3、相关参数验证。分析传入的timestamp是否正常
		 */
		String timestamp=params.get("timestamp");
		boolean isValid=compareTimeDiff(Long.parseLong(timestamp),24*60);
		if(isValid==false){
			logger.error("[ip="+request.getRemoteAddr()+"] 请求的时间戳异常!timestamp="+timestamp);
			StringHelper.renderResponse(response, ResponseMessage.error("请求的时间戳异常!"));
			return false;
		}
		
		/**
		 * 4、生成本地签名，并分析传来的签名是否和本地签名一致。
		 */
		String localSign=MD5_fromWxpay.generateSignature(params,Constants.AES_KEY);
		if(localSign.equals(sign)){
			logger.info("验签通过!sign="+sign);
			return true;
		}else{
			logger.error("验签未通过! sign="+sign+"\tlocalSign="+localSign);
			StringHelper.renderResponse(response, ResponseMessage.error("验签未通过!"));
			return false;
		}
	}
	
	
	/**
	 * 分析时间差是否在给定范围内。
	 * <br>分析timestamp和当前时间之差是否在给定范围内。
	 * @param
	 * @return
	 * @author cjw 2019-11-27
	 */
	public static boolean compareTimeDiff(long timestamp,long allowMinute){
		long diff=Math.abs(System.currentTimeMillis()-timestamp);
		long allowMillisecond=allowMinute*60*1000;
		if(diff<=allowMillisecond){
			return true;
		}else{
			return false;
		}
	}
	
	
	
	
	
	
	
	
	
	
	
}
